    //Random Game Engine
    //Copyright (C) 2012  Nikolay Dionisov

    //This program is free software: you can redistribute it and/or modify
    //it under the terms of the GNU General Public License as published by
    //the Free Software Foundation, either version 3 of the License, or
    //(at your option) any later version.

    //This program is distributed in the hope that it will be useful,
    //but WITHOUT ANY WARRANTY; without even the implied warranty of
    //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    //GNU General Public License for more details.

    //You should have received a copy of the GNU General Public License
    //along with this program.  If not, see <http://www.gnu.org/licenses/>.

	//------------------------------------------------------------------------

	//FILE NAME: CoreInterfaces.h
	//Interfaces of the all objects, living uder the "core" namespace.
	//-Struct AppSettings
	//-Class IOSFramework

#pragma once
#include "BasicTypes\BaseTypes.h"
#include "Synchronization\RealtimeDataTypes.h"
#include <memory>

#define RE_NEW new // for now, here. When the memory module is ready, this will be moved

enum RER_TYPE;
class IRenderer;

namespace re
{
	namespace core
	{
		//----------------------------------------------------------------------------------------------//
		//----------------------------------------------------------------------------------------------//
		//App Settings. Struct containing the runtime settings and variables of the typical window app.
		//Beeing used by the OS Framework
		//----------------------------------------------------------------------------------------------//
		//----------------------------------------------------------------------------------------------//
		typedef struct _AppSettings
		{
			U32 width, height; // what shoud be the size of the our window?
			std::wstring app_name; // what shoud be writtonon our window?
			bool is_running; // should the main loop be alive?
		}AppSettings;

		//----------------------------------------------------------------------------------------------//
		//----------------------------------------------------------------------------------------------//
		//OS Framework interfaces. Purpose: Communciation with the OS using the same set of functions.
		//----------------------------------------------------------------------------------------------//
		//----------------------------------------------------------------------------------------------//


		//---------------------------------------------------------------------------------------
		//ThreadForwarder(Interface and implementation). Delegate used to tell the new thread where it shoud go
		//---------------------------------------------------------------------------------------
		class IThreadForwarder
		{
		public:
			IThreadForwarder() {}
			~IThreadForwarder() {}
			virtual void FollowThread() = 0;
		};
		template<class T>
		class ThreadForwarder : public IThreadForwarder
		{
		public:
			typedef void (T::*receiver_function_type)(void);
			ThreadForwarder(T* rec, receiver_function_type rf) : receiver_(rec), recfunc(rf)  {}
			~ThreadForwarder() {}
			
			virtual void FollowThread()
			{
				(receiver_->*recfunc)();
			}
		private:
			T* receiver_;
			receiver_function_type recfunc;
		};

		template<class T>
		class IOSFramework
		{
		public:
			IOSFramework() {}
			~IOSFramework() {}

			typedef void (T::*pointer_void_void)(void);
			typedef void (T::*pointer_void_renderer)(IRenderer*);
			typedef bool (T::*pointer_bool_void)(void);

			virtual void SetCallbackReceiver(T* receiver) = 0;
			virtual void SetCallbackCreateDevice(pointer_void_renderer clb) = 0;
			virtual void SetCallbackDestroyDevice(pointer_void_void clb) = 0;
			virtual void SetCallbackLostDevice(pointer_void_void clb) = 0;
			virtual void SetCallbackResetDevice(pointer_void_void clb) = 0;
			virtual void SetCallbackUpdate(pointer_bool_void clb) = 0;
			virtual void SetCallbackRender(pointer_void_void clb) = 0;

			virtual void CreateThread(IThreadForwarder* thread_forwarder) = 0;

			virtual void VInitialize(AppSettings* settings, RER_TYPE renderer_type) = 0;
			virtual void VShutDown() = 0;
			virtual void VRun() = 0;
		};

		
		//----------------------------------------------------------------------------------------------//
		//----------------------------------------------------------------------------------------------//
		//EventManager
		//----------------------------------------------------------------------------------------------//
		//----------------------------------------------------------------------------------------------//
		typedef U32 EventType;
		class IEventData;
		typedef std::tr1::shared_ptr<IEventData> EventDataPtr;
		class IEventData
		{
		public:
			IEventData() {}
			~IEventData() {}

			virtual EventType VGetEventTypeId() = 0;
			virtual EventDataPtr VCreateCopy() = 0;
			virtual void VGetEventDataAsString(std::wstring & data) = 0;
		};
		class IEventListener
		{
		public:
			IEventListener() {}
			~IEventListener() {}

			virtual void VHandleEvent(EventDataPtr data) = 0;
		};
		class RealtimeEventListener : public IEventListener
		{
		public:
			RealtimeEventListener() {}
			~RealtimeEventListener() {}
			virtual void VHandleEvent(EventDataPtr data)
			{
				queue_.push(data->VCreateCopy());
			}
			RealtimeQueue<EventDataPtr> queue_;
		};
		typedef std::tr1::shared_ptr<IEventListener> EventListenerPtr;
#define GetEventManager() re::core::IEventManager::GetGlobal()
		class IEventManager
		{
		public:
			IEventManager() { this_ = this; }
			~IEventManager() {}

			virtual void VTriggerEvent(EventDataPtr data) = 0;
			virtual void VQueueEvent(EventDataPtr data) = 0;

			virtual void VTick() = 0;

			virtual void VRegisterEvent(EventType type) = 0;

			virtual void VRegisterListener(EventListenerPtr listener) = 0;
			virtual void VRegisterListener(EventListenerPtr listener, EventType type) = 0;

			static IEventManager* GetGlobal() { return this_; }
		private:
			static IEventManager* this_;
		};

	}
}